package com.sydsen.imager.util;

import com.sydsen.imager.ImageOptions;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.image.BufferedImage;
import java.awt.image.ColorConvertOp;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import java.util.regex.Pattern;

/**
 * @Auther: syh
 * @Date: 2021/9/16
 * @Description:
 */
public class ImageUtils {

    private static final Pattern PATTERN =
            Pattern.compile("(https?|ftp|file)://[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]");

    /**
     * 读取图片对象
     *
     * @param imagePath
     * @return
     * @throws IOException
     */
    public static BufferedImage read(String imagePath) throws IOException {
        if (PATTERN.matcher(imagePath).find()) {
            return ImageIO.read(new URL(imagePath));
        } else {
            return ImageIO.read(new File(imagePath));
        }
    }

    public static void write(String filePath, BufferedImage img, String ext) throws Exception {
        if (img != null) {
            File file = new File(filePath);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdir();
            }
            ImageIO.write(img, ext, new File(filePath));
        } else {
            throw new Exception("尚未执行图片合成，无法保存文件");
        }
    }

    public static BufferedImage createImage(int width, int height) {
        return createImage(width, height, Color.GRAY);
    }

    public static BufferedImage createImage(int width, int height, Color color) {
        return createImage(width, height, color, ImageOptions.PicType.JPG);
    }

    public static BufferedImage createPngImage(int width, int height) {
        return createImage(width, height, null, ImageOptions.PicType.PNG);
    }

    public static BufferedImage createImage(int width, int height, Color color, ImageOptions.PicType outputFormat) {
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        /**2、得到画笔对象*/
        Graphics2D g2d = buffImg.createGraphics();
        if (outputFormat == ImageOptions.PicType.PNG) {
            // ----------  增加下面的代码使得背景透明  -----------------
            buffImg = g2d.getDeviceConfiguration()
                    .createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            g2d.dispose();
            g2d = buffImg.createGraphics();
            // ----------  背景透明代码结束  -----------------
        }
        // 设置对线段的锯齿状边缘处理
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        if (ImageOptions.PicType.PNG != outputFormat) {
            // 设置颜色
            g2d.setColor(color);

            // 颜色填充
            g2d.fillRect(0, 0, buffImg.getWidth(), buffImg.getHeight());
        }

        //释放资源
        g2d.dispose();
        return buffImg;
    }


    public static BufferedImage waterMarkByText(int width, int height, String text, Color color,
                                                Font font, Double degree, float alpha, ImageOptions.PicType outputFormat) {
        BufferedImage buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        /**2、得到画笔对象*/
        Graphics2D g2d = buffImg.createGraphics();
        if (outputFormat == ImageOptions.PicType.PNG) {
            // ----------  增加下面的代码使得背景透明  -----------------
            buffImg = g2d.getDeviceConfiguration()
                    .createCompatibleImage(width, height, Transparency.TRANSLUCENT);
            g2d.dispose();
            g2d = buffImg.createGraphics();
            // ----------  背景透明代码结束  -----------------
        }
        // 设置对线段的锯齿状边缘处理
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
                RenderingHints.VALUE_INTERPOLATION_BILINEAR);

        // 设置水印旋转
        if (null != degree) {
            //注意rotate函数参数theta，为弧度制，故需用Math.toRadians转换一下
            //以矩形区域中央为圆心旋转
            g2d.rotate(Math.toRadians(degree), (double) buffImg.getWidth() / 2,
                    (double) buffImg.getHeight() / 2);
        }

        // 设置颜色
        g2d.setColor(color);

        // 设置 Font
        g2d.setFont(font);

        //设置透明度:1.0f为透明度 ，值从0-1.0，依次变得不透明
        g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
        //获取真实宽度
        float realWidth = getRealFontWidth(text);
        float fontSize = font.getSize();
        //计算绘图偏移x、y，使得使得水印文字在图片中居中
        //这里需要理解x、y坐标是基于Graphics2D.rotate过后的坐标系
        float x = 0.5f * width - 0.5f * fontSize * realWidth;
        float y = 0.5f * height + 0.5f * fontSize;
        //取绘制的字串宽度、高度中间点进行偏移，使得文字在图片坐标中居中
        g2d.drawString(text, x, y);
        //释放资源
        g2d.dispose();
//        System.out.println("添加水印文字完成!");
        return buffImg;

    }

    /**
     * 获取真实字符串宽度，ascii字符占用0.5，中文字符占用1.0
     */
    private static float getRealFontWidth(String text) {
        int len = text.length();
        float width = 0f;
        for (int i = 0; i < len; i++) {
            if (text.charAt(i) < 256) {
                width += 0.5f;
            } else {
                width += 1.0f;
            }
        }
        return width;
    }

    /**
     * 圆角
     * @param srcImage
     * @param width
     * @param height
     * @param radius
     * @return
     */
    public static BufferedImage makeRoundCorner(BufferedImage srcImage, int width, int height, int radius) {
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.fillRoundRect(0, 0, width, height, radius, radius);
        g.setComposite(AlphaComposite.SrcIn);
        g.drawImage(srcImage, 0, 0, width, height, null);
        g.dispose();
        return image;
    }

    /**
     * 高斯模糊
     * @param image
     * @param radius
     * @return
     */
    public static BufferedImage makeBlur(BufferedImage image, int radius) {
        int x, y, quantum, x_distance, y_distance;

        BufferedImage bimg = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Random rand = new Random(System.currentTimeMillis());

        quantum = radius;
        for (y = 0; y < image.getHeight(); y++) {
            for (x = 0; x < image.getWidth(); x++) {
                do {
                    x_distance = (int) (((2 * (double) radius + 1) * rand.nextDouble()) - quantum);
                    y_distance = (int) (((2 * (double) radius + 1) * rand.nextDouble()) - quantum);
                } while ((x + x_distance < 0 || y + y_distance < 0) || x + x_distance > image.getWidth()
                        || y + y_distance > image.getHeight());
                try {
                    bimg.setRGB(x, y, image.getRGB(x + x_distance, y + y_distance));
                } catch (Exception e) {

                }
            }
        }
        return bimg;
    }

    /**
     * 删除指定颜色(变透明)
     *
     * @param srcImage
     * @param alpha
     * @return
     * @throws IOException
     */
    public static BufferedImage alpha(BufferedImage srcImage, Color color,
                                                 int alpha) throws IOException {
        int imgHeight = srcImage.getHeight();   //取得原图的长和宽
        int imgWidth = srcImage.getWidth();

        //防止越位
        alpha = alpha > 10 ? 10 : alpha < 0 ? 0 : alpha;

        //新建一个类型支持透明的BufferedImage
        BufferedImage tmpImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_4BYTE_ABGR);

        for (int i = 0; i < imgWidth; ++i) { //把原图片的内容复制到新的图片，同时把背景设为透明
            for (int j = 0; j < imgHeight; ++j) {
                int rgb = srcImage.getRGB(i, j);
                //把背景设为透明
                rgb = rgb == color.getRGB() ? (((alpha * 255 / 10) << 24) | (rgb & 0x00ffffff)) : rgb;
                tmpImg.setRGB(i, j, rgb);
            }
        }
        return tmpImg;
    }

    /**
     * 渐变
     * @param srcImg
     * @param from
     * @param to
     * @param opacity
     * @return
     */
    public static BufferedImage drawGradient(BufferedImage srcImg, Color from, Color to, float opacity) {
        return drawGradient(srcImg, 0, 0, srcImg.getWidth(), srcImg.getHeight(), from, to, opacity);
    }

    public static BufferedImage drawGradient(BufferedImage srcImg,
                                             int startX, int startY,
                                             int endX, int endY,
                                             Color colorFrom, Color colorTo,
                                             float opacity) {
        BufferedImage dstImg = new BufferedImage(srcImg.getWidth(), srcImg.getHeight(), BufferedImage.TYPE_INT_ARGB);
        GradientPaint grad = new GradientPaint(startX, startY, colorFrom, endX, endY, colorTo); //从左上到右下渐变;

        Graphics2D g2 = (Graphics2D) dstImg.getGraphics();
        g2.setPaint(grad);
        g2.fillRect(startX, startY, endX, endY);

        g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, opacity));
        g2.drawImage(srcImg, 0, 0, srcImg.getWidth(), srcImg.getHeight(), null);
        g2.dispose();

        return dstImg;
    }

    /**
     * 图片翻转
     * @param inputImage
     * @param flip
     * @return
     */
    public static BufferedImage flipImage(final BufferedImage inputImage, ImageOptions.Flip flip) {
        int w = inputImage.getWidth();
        int h = inputImage.getHeight();
        BufferedImage img = null;
        Graphics2D graphics2d = null;
        if (ImageOptions.Flip.HORIZONTAL.equals(flip)) {
            (graphics2d = (img = new BufferedImage(w, h, inputImage
                    .getColorModel().getTransparency())).createGraphics())
                    .drawImage(inputImage, 0, 0, w, h, w, 0, 0, h, null);
        } else if(ImageOptions.Flip.VERTICAL.equals(flip)) {
            (graphics2d = (img = new BufferedImage(w, h, inputImage
                    .getColorModel().getTransparency())).createGraphics())
                    .drawImage(inputImage, 0, 0, w, h, 0, h, w, 0, null);
        }
        graphics2d.dispose();
        return img;
    }

    /**
     *
     * @param inputImage
     * @return
     */
    public final static BufferedImage toGray(BufferedImage inputImage)
    {
        ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
        //对源 BufferedImage 进行颜色转换。如果目标图像为 null，
        //则根据适当的 ColorModel 创建 BufferedImage。
        ColorConvertOp op = new ColorConvertOp(cs, null);
        return op.filter(inputImage, null);
    }
}
